/**
 * Class: EventList
 *
 * Purpose: 
 *
 * Created: Jan 30, 2010 @ 3:35:33 PM
 * @author Ken Scott
 */
package org.openfantasia.musica.events;

import org.openfantasia.musica.Musica;
import org.openfantasia.util.time.PrecisionClock;
import org.openfantasia.util.time.PrecisionClockListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EventList extends Event {

	protected Map<Long, List<Event>> events = new HashMap<Long, List<Event>>();

	protected Event mostRecentlyAdded;


	protected EventList() {
	}


	public EventList(Musica mc) {
		super(mc);
	}


	public EventList(EventList that) {
		copy(that);
	}


	public EventList copy() {
		return new EventList(this);
	}


	public void copy(EventList that) {
		super.copy(that);

		this.events.clear();
		for (long time : that.events.keySet()) {
			List<Event> evts = new ArrayList<Event>(that.events.get(time));
			for (Event evt : evts) {
				this.add(evt.copy(), time);
			}
		}
	}


	public void addAll(List<Event> events) {
		for (Event event : events) {
			add(event);
		}
	}


	public void addAll(List<Event> events, long time) {
		for (Event event : events) {
			add(event, time);
		}
	}


	public void add(Event event) {
		long time = event.getTime();
		add(event, time);
	}


	public void addAfter(Event event) {
		long time = 0;
		if (mostRecentlyAdded != null) {
			time = mostRecentlyAdded.getTime() + mostRecentlyAdded.getDuration();
		}
		add(event, time);
		mostRecentlyAdded = event;
	}


	public void addOver(Event event) {
		long time = 0;
		if (mostRecentlyAdded != null) {
			time = mostRecentlyAdded.getTime();
		}
		add(event, time);
	}


	public void add(Event event, long time) {
		if (time == Event.INVALID_TIME) {
			throw new IllegalArgumentException("Event time was not set");
		}
		if (time < 0) {
			throw new IllegalArgumentException("Event time is invalid: " + time);
		}
		event.setTime(time);		// in case it wasn't setVertices before

		List<Event> sub = events.get(time);
		if (sub == null) {
			sub = new ArrayList<Event>();
			events.put(time, sub);
		}
		sub.add(event);
	}


	public List<Event> getEvents(long time) {
		return events.get(time);
	}


	public List<Event> getAllEvents() {
		List<Event> result = new ArrayList<Event>();
		for (List<Event> sub : events.values()) {
			result.addAll(sub);
		}
		return result;
	}


	public void transpose(Event event, int amount) {
		List<Event> events = ((EventList) event).getAllEvents();
		for (Event evt : events) {
			evt.transpose(evt, amount);
		}
	}


	public void action() {
	}


	public void play() {
		final PrecisionClock pclock = new PrecisionClock();
		pclock.addListener(new PrecisionClockListener() {
			long startTime = -1L;

			long previousTime = -1L;


			public void tick(long tickCount, long currentTimeNanos, long cycleTimeNanos) {
				if (previousTime == -1L) {
					startTime = currentTimeNanos;
					previousTime = 0;
				}
				long now = currentTimeNanos - startTime;
				long prev = previousTime;
				previousTime = now + 1;

				List<Event> subs = getEvents(tickCount);
				if ((subs != null) && !subs.isEmpty()) {
					for (Event event : subs) {
						event.action();
					}
				}
			}
		});
		pclock.start(musica.getNsPerTick());
		musica.start();
	}
}
